package com.mf.dao.framework;

import com.mf.domain.general.PageBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.persistence.Id;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;

/**
 * DAO通用实现
 * User: zhaoming
 * Date: 2016-06-24
 * To change this template use File | Settings | File Templates.
 **/
public class GenericDao<T extends Object> extends BaseDao<T> implements IDao<T>, IMapper{

    public Logger logger = LoggerFactory.getLogger(getClass());

    public static final String INSERT                               = "insert";                         //新增
    public static final String BATCH_INSERT                         = "batchInsert";                    //批量新增
    public static final String UPDATE_BY_PRIMARY_KEY                = "updateByPrimaryKey";             //根据主键修改
    public static final String DELETE_BY_PRIMARY_KEY                = "deleteByPrimaryKey";             //根据主键删除(物理)
    public static final String DELETE_BY_PRIMARY_KEYS               = "deleteByPrimaryKeys";            //根据主键批量删除(物理)
    public static final String DELETE_BY_PRIMARY_KEY_LOGICALLY      = "deleteByPrimaryKeyLogically";    //根据主键删除(逻辑)
    public static final String DELETE_BY_PRIMARY_KEYS_LOGICALLY     = "deleteByPrimaryKeysLogically";   //根据主键批量删除(逻辑)
    public static final String SELECT_BY_PRIMARY_KEY                = "selectByPrimaryKey";             //根据主键查询
    public static final String SELECT_BY_CONDITION                  = "selectByCondition";              //根据条件查询
    public static final String SELECT_COUNT                         = "selectCount";                    //根据条件查询数量
    public static final String PAEG_SELECT_SQL                      = "pageSelectSql";                  //分页条件查询

    private final Class<T> entityClass;     // 数据实体类定义

    /**
     * 构造函数
     */
    public GenericDao() {
        Type type = getClass().getGenericSuperclass();
        Type[] params = ((ParameterizedType) type).getActualTypeArguments();
        this.entityClass = (Class<T>) params[0];
    }

    /**
     * 新增实体对象
     * @param entity 实体对象
     * @return 执行结果 (true:成功; false:失败)
     */
    public boolean insert(T entity){
        return this.insert(this.getStatement(INSERT), entity);
    }

    /**
     * 批量新增实体对象
     * @param entities 实体对象列表
     * @return 执行结果 (true:成功; false:失败)
     */
    public boolean batchInsert(List<T> entities){
        return this.insert(this.getStatement(BATCH_INSERT), entities);
    }

    /**
     * 根据主键修改实体对象
     * @param entity 实体对象
     * @return 执行结果 (true:成功; false:失败)
     */
    public boolean updateByPrimaryKey(T entity){
        return this.update(this.getStatement(UPDATE_BY_PRIMARY_KEY), entity);
    }

    /**
     * 根据主键删除实体对象(物理删除)
     * @param id 主键
     * @return 执行结果 (true:成功; false:失败)
     */
    public boolean deleteByPrimaryKey(Long id){
        T entity = null;
        try {
            entity = entityClass.newInstance();
            Field[] superFields = entity.getClass().getSuperclass().getDeclaredFields();
            for(Field field : superFields){
                Id idAnnotation = field.getAnnotation(Id.class);
                if(idAnnotation != null){
                    field.setAccessible(true);
                    field.set(entity, id);
                }
            }
            Field[] fields = entity.getClass().getDeclaredFields();
            for(Field field : fields){
                Id idAnnotation = field.getAnnotation(Id.class);
                if(idAnnotation != null){
                    field.setAccessible(true);
                    field.set(entity, id);
                }
            }
        }  catch (Exception e) {
            e.printStackTrace();
        }
        return this.deleteByPrimaryKey(entity);
    }

    /**
     * 根据主键删除实体对象(物理删除)
     * @param entity 实体对象
     * @return 执行结果 (true:成功; false:失败)
     */
    public boolean deleteByPrimaryKey(T entity){
        return this.delete(this.getStatement(DELETE_BY_PRIMARY_KEY), entity);
    }

    /**
     * 根据主键批量删除实体对象
     * @param entities 实体对象列表
     * @return 执行结果 (true:成功; false:失败)
     */
    public boolean deleteByPrimaryKeys(List<T> entities){
        return this.delete(this.getStatement(DELETE_BY_PRIMARY_KEYS), entities);
    }

    /**
     * 根据主键删除实体对象(逻辑删除)
     * @param entity 实体对象
     * @return 执行结果 (true:成功; false:失败)
     */
    public boolean deleteByPrimaryKeyLogically(T entity){
        return this.update(this.getStatement(DELETE_BY_PRIMARY_KEY_LOGICALLY), entity);
    }

    /**
     * 根据主键批量删除实体对象
     * @param entities 实体对象列表
     * @return 执行结果 (true:成功; false:失败)
     */
    public boolean deleteByPrimaryKeysLogically(List<T> entities){
        return this.deleteLogically(this.getStatement(DELETE_BY_PRIMARY_KEYS_LOGICALLY), entities);
    }

    /**
     * 根据主键查询实体对象
     * @param id 主键
     * @return 实体对象
     */
    public T selectByPrimaryKey(Long id){
        T entity = null;
        try {
            entity = entityClass.newInstance();
            Field[] superFields = entity.getClass().getSuperclass().getDeclaredFields();
            for(Field field : superFields){
                Id idAnnotation = field.getAnnotation(Id.class);
                if(idAnnotation != null){
                    field.setAccessible(true);
                    field.set(entity, id);
                }
            }
            Field[] fields = entity.getClass().getDeclaredFields();
            for(Field field : fields){
                Id idAnnotation = field.getAnnotation(Id.class);
                if(idAnnotation != null){
                    field.setAccessible(true);
                    field.set(entity, id);
                }
            }
        }  catch (Exception e) {
            e.printStackTrace();
        }
        return this.selectOne(this.getStatement(SELECT_BY_PRIMARY_KEY), entity);
    }

    /**
     * 根据主键查询实体对象
     * @param entity 实体对象
     * @return 实体对象
     */
    public T selectByPrimaryKey(T entity){
        return this.selectOne(this.getStatement(SELECT_BY_PRIMARY_KEY), entity);
    }

    /**
     * 根据条件查询实体对象列表
     * @param entity 实体对象
     * @return 实体对象列表
     */
    public List<T> selectByCondition(T entity) {
        return this.selectList(this.getStatement(SELECT_BY_CONDITION), entity);
    }

    /**
     * 根据条件查询实体对象数量
     * @param entity 实体对象
     * @return 实体对象列表
     */
    public Integer selectByConditionCount(T entity) {
        return this.selectCount(this.getStatement(SELECT_COUNT), entity);
    }

    /**
     * 分页查询实体对象列表
     * @param pageBean 分页实体
     * @param entity 实体对象
     * @return 实体对象列表
     */
    public PageBean<T> pageQuery(PageBean pageBean, T entity){
        return this.pageQuery(this.getStatement(PAEG_SELECT_SQL), this.getStatement(SELECT_COUNT), pageBean, entity);
    }

    /**
     * 获取映射文件命名空间 ，默认使用DAO实例的类名
     *
     * @return 映射文件命名空间
     */
    public String getNamespace(){
        // 本系统将DAO接口作为命名空间
        Class<?>[] clazzes = this.getClass().getInterfaces();
        // 如果DAO没有继承接口
        if (clazzes == null || clazzes.length < 1) {
            throw new RuntimeException("DAO实现类需要实现接口，同时该接口名作为Mapper命名空间");
        }
        return clazzes[0].getName();
    }

    /**
     * 获取SQL语句在映射文件中的id
     *
     * @return SQL语句在映射文件中的id
     */
    public String getStatement(String statementKey){
        return this.getNamespace() + "." + statementKey;
    }
}
